package com.xiashitech.agent.db.dao.extload;

import cn.hutool.core.util.HashUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
// import com.xiashitech.agent.cache.authquery.extload.DesensitiseRuleLFUCache;
import com.xiashitech.agent.cache.authquery.extloadproxy.DesensitiseRuleLFUCacheProxy;
// import com.xiashitech.agent.cache.authquery.extload.UserPermissionLFUCache;
import com.xiashitech.agent.cache.authquery.extloadproxy.UserPermissionLFUCacheProxy;
import com.xiashitech.agent.constants.XSConstants;
import com.xiashitech.agent.db.extload.LocalDataSource;
import com.xiashitech.agent.db.entity.UserPermission;
import com.xiashitech.agent.utils.XSUtil;

import java.sql.SQLException;
import java.util.List;

public class UserPermissionDao {

    public void saveInitData(List<UserPermission> userPermissionList){
        // if the collection size > 1, it will execute in batches.
        //Db.use(LocalDataSource.getDS()).insert(entities);
        for (UserPermission userPermission : userPermissionList){
            try {
                Entity entity = Entity.create(UserPermission.TABLE_NAME).parseBean(userPermission, true, true);
                Db.use(LocalDataSource.getDS()).insert(entity);
            }catch (RuntimeException | SQLException e){
                XSUtil.debug("Insert ERROR {}", e.getMessage());
            }
        }
    }

    //用户组权限发生变更
    public void saveChangeData(List<UserPermission> userPermissionList) {
        for (UserPermission up : userPermissionList){
            try {
                //授权逻辑有点绕： Status 1（*Auth:true）: 明确授权可以访问  Status -1(*Auth:false): 明确授权不可以访问；没有授权的初始状态不会传到这里来。
                //目前逻辑 Status 是无实际意义的字段。
                Entity entity = Entity.create(UserPermission.TABLE_NAME).parseBean(up, true, true);
                if (StrUtil.equalsIgnoreCase(up.getStatus(), XSConstants.UserPermissionStatus.NO_ACCESS) || StrUtil.equalsIgnoreCase(up.getStatus(), XSConstants.UserPermissionStatus.ACCESS)){
                    //CREATE OR UPDATE
                    Db.use(LocalDataSource.getDS()).upsert(entity, "USER_ID", "INSTANCE_NAME", "DATABASE_NAME", "SCHEMA_NAME", "TAB_NAME", "COL_NAME", "OPERATE");
                }else {
                    XSUtil.debug("[WARNING] unknown data STATUS! [entity]{}", entity);
                }
            }catch (RuntimeException | SQLException e){
                XSUtil.debug("ERROR {}", e.getMessage());
            }
        }
    }

    // 用户组用户发生变更（新增和删除）
    public void saveChangeDataUserGroupBased(List<UserPermission> userPermissionList) {
        for (UserPermission up : userPermissionList){
            try {
                Entity where = Entity.create().set("USER_ID", up.getUserId()).set("INSTANCE_NAME", up.getInstanceName())
                        .set("DATABASE_NAME", up.getDatabaseName()).set("SCHEMA_NAME", up.getSchemaName()).set("TAB_NAME", up.getTabName())
                        .set("COL_NAME", up.getColName()).set("OPERATE", up.getOperate());
                if (StrUtil.equalsIgnoreCase(up.getUserAction(), XSConstants.UserAction.DELETE)){
                    Db.use(LocalDataSource.getDS()).del(where.setTableName(UserPermission.TABLE_NAME));
                }else if (StrUtil.equalsIgnoreCase(up.getUserAction(), XSConstants.UserAction.ADD)) {
                    Entity entity = Entity.create(UserPermission.TABLE_NAME).parseBean(up, true, true);
                    Db.use(LocalDataSource.getDS()).insert(entity);
                }else {
                    XSUtil.debug("[WARNING] unknown userAction!");
                }
            }catch (Throwable throwable){
                XSUtil.debug("ERROR {}", throwable.getMessage());
            }
        }
    }

    public void truncate() throws SQLException{
        Db.use(LocalDataSource.getDS()).execute("TRUNCATE TABLE " + UserPermission.TABLE_NAME);
    }

    public List<UserPermission> list(String userId, String schemaName, String tableName, String operate) throws SQLException {
        List<UserPermission> userPermissionList;
        String cacheKey = cacheKey(userId, schemaName, tableName, operate);
        // Cache Get（考虑缓存穿透场景）
        if(UserPermissionLFUCacheProxy.hasKey(cacheKey)){
            return UserPermissionLFUCacheProxy.get(cacheKey);
        }
        String sql = "SELECT ID,TAB_AUTH,IFNULL(TAB_AUTH_REASON, 'none') TAB_AUTH_REASON,COL_NAME,COL_AUTH,IFNULL(COL_AUTH_REASON, 'none') COL_AUTH_REASON FROM USER_PERMISSION WHERE USER_ID = ? AND SCHEMA_NAME = ? AND TAB_NAME = ? AND OPERATE = ? AND COL_NAME IS NOT NULL";
        userPermissionList = Db.use(LocalDataSource.getDS()).query(sql, UserPermission.class, userId, schemaName, tableName, operate);
        // Cache Put
        UserPermissionLFUCacheProxy.add(cacheKey, userPermissionList);
        return userPermissionList;
    }

    private String cacheKey(String userId, String schemaName, String tableName, String operate){
        String cacheKey = StrUtil.format("{}:{}:{}:{}", userId, schemaName, tableName, operate);
        return String.valueOf(HashUtil.apHash(cacheKey));
    }

    public long count(){
        long cnt = -1;
        try {
            cnt = Db.use(LocalDataSource.getDS()).count(Entity.create(UserPermission.TABLE_NAME));
        }catch (SQLException e) {
            XSUtil.debug("SQL COUNT ERROR: {}" + e.getMessage());
        }
        return cnt;
    }

    public void printAllPermission(String soureFunction){
        try {
            String sql = "SELECT * FROM USER_PERMISSION";
            List<UserPermission> userPermissionList = Db.use(LocalDataSource.getDS()).query(sql, UserPermission.class);
            long batchTs = System.nanoTime();
            if(userPermissionList != null && userPermissionList.size() > 0) {
                for (UserPermission up : userPermissionList) {
                    System.out.println(Thread.currentThread().getId() + " T" + batchTs + " DesenseDebug, printAllPermission, " + soureFunction + ": " + up.toString());
                }
            } else {
                System.out.println(Thread.currentThread().getId() + " T" + batchTs + " DesenseDebug, printAllPermission, " + soureFunction + ": permission size is 0");
            }
        }catch (SQLException e) {
            XSUtil.debug("SQL printAllPermission ERROR: {}" + e.getMessage());
        }
    }

}
